package com.viewhigh.wechat.sdk.api;


import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.sword.lang.HttpUtils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.viewhigh.framework.common.log.LogUtils;
import com.viewhigh.wechat.sdk.bean.AccessTokenCacheBean;
import com.viewhigh.wechat.sdk.bean.AccountCacheBean;
import com.viewhigh.wechat.sdk.cache.AccessTokenCache;

/**
 * 
* @ClassName: AccessTokenApi
* @Description: 微信公众号授权API
* @author liusongqing
* @date 2016年9月26日 下午3:20:33 
*
 */
public class AccessTokenApi {
    private static int requestTimes = 4;//token请求失败后重新请求的次数
    private static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential";
    
    /**
     * 
    * @Title: getAccessToken 
    * @Description: 从缓存中获取指定appId下的缓存对象 AccessTokenCacheBean
    * @param @param appId
    * @param @return    设定文件 
    * @return AccessTokenCacheBean    返回类型 
    * @throws
     */
    public static synchronized AccessTokenCacheBean getAccessToken(String appId) {
        AccessTokenCacheBean result = AccessTokenCache.get(appId);
        if (result != null && result.isAvailable()) {
            LogUtils.error("AccessTokenApi 从redis缓存获取微信Token，appid="+appId+"token="+result.getAccessToken()+"有效时间="+result.getExpiredTime());
            return result;
        }
        refreshAccessToken(appId);
        AccessTokenCacheBean test = AccessTokenCache.get(appId);
        return test;
    }
    
    /**
     * 
    * @Title: refreshAccessToken 
    * @Description: 刷新 AccessTokenCacheBean 缓存 
    * @param @param appId    设定文件 
    * @return void    返回类型 
    * @throws
     */
    public static synchronized void refreshAccessToken(String appId) {
        LogUtils.error("AccessTokenApi 刷新 AccessTokenCacheBean 缓存，appid="+appId);
        AccountCacheBean accountCacheBean = AccountApi.getAccessCacheBean(appId);
        if(null != accountCacheBean){
            String appSecret = accountCacheBean.getAppSecret();
            if(StringUtils.isNotBlank(appSecret)){
                String url = accessTokenUrl(appId,appSecret);
                for(int i=0;i<requestTimes;i++){
                    //请求成功则退出
                    AccessTokenCacheBean result = request(url);
                    if(null != result){
                        AccessTokenCache.set(appId, result);
                        break;
                    }          
                }
            }else{
                LogUtils.error("AccessTokenApi 获取appSecret为空！appid="+appId);
            }
        }else{
            LogUtils.error("AccessTokenApi 获取微信账号缓存失败，appid="+appId);
        }
       
    }
    
    /**
     * 直接获取 accessToken 字符串，方便使用
     * 
     * @return String accessToken
     */
    public static String getAccessTokenStr(String appId) {
        return getAccessToken(appId).getAccessToken();
    }
    
    /**
     * 请求信的access token
     * http请求方式: GET
        https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
        {"access_token":"ACCESS_TOKEN","expires_in":7200}
        {"errcode":40013,"errmsg":"invalid appid"}
     */
    public static AccessTokenCacheBean request(String url){
        AccessTokenCacheBean accessTokenBean = new AccessTokenCacheBean();
        String result = HttpUtils.get(url);
        if(StringUtils.isBlank(result))
            return null;
        if(!parseData(result)){
            return null;
        }
        try {
            Map<String, Object> temp = JSON.parseObject(result, Map.class);
            accessTokenBean.setAccessToken((String) temp.get("access_token"));
            Integer expiresIn = getInt(temp, "expires_in");
            accessTokenBean.setExpiresIn(expiresIn);
            accessTokenBean.setErrcode(getInt(temp, "errcode"));
            accessTokenBean.setErrmsg((String) temp.get("errmsg"));
            
            if (getInt(temp, "expires_in") != null) {
                accessTokenBean.setExpiredTime( System.currentTimeMillis() + ((expiresIn - 200) * 1000));
            }
        } catch (Exception e) {
           e.printStackTrace();
           LogUtils.error("解析AccessToken result失败:"+accessTokenBean.getAccessToken(),e);
           return null;
        }
        LogUtils.error("AccessTokenApi 刷新token成功 ！AccessToken:"+accessTokenBean.getAccessToken()+"有效时间="+accessTokenBean.getExpiredTime());
        return accessTokenBean;
    }
    
    /**
     * 
    * @Title: checkAccessToken 
    * @Description: 微信公众号配置验证
    * @param @param appId
    * @param @param appSecret
    * @param @return    设定文件 
    * @return Boolean    返回类型 
    * @throws
     */
    public static synchronized Boolean checkAccessToken(String appId,String appSecret){
        AccessTokenCacheBean result = null;
        if(StringUtils.isBlank(appId) || StringUtils.isBlank(appSecret)){
            return false;
        }
        result = AccessTokenCache.get(appId);
        if (result != null && result.isAvailable()) {
            return true;
        }
        String url = accessTokenUrl(appId,appSecret);
        result = request(url);
        if(null != result){
            if(null != AccessTokenCache.get(appId)){
                AccessTokenCache.remove(appId);
            }
            AccessTokenCache.set(appId, result);
            return true;
        }else{
            return false;   
        }
    }
    /**
     * 组织accesstoken的请求utl
     */
    private static String accessTokenUrl(String appid,String appsecret) {
        String url = ACCESS_TOKEN_URL + "&appid=" + appid + "&secret=" + appsecret;
        LogUtils.debugLog("创建获取access_token url");
        return url;
    }
    
    /**
     * 解析token数据
     * @param data
     * @return
     */
    private static boolean parseData(String data){
        JSONObject jsonObject = JSONObject.parseObject(data);
        String tokenName = "access_token";
        String expiresInName = "expires_in";
        try {
            String token = jsonObject.get(tokenName).toString();
            if(StringUtils.isBlank(token)){
                LogUtils.error("token获取失败,获取结果" + data);
                return false;
            }
            String expiresIn = jsonObject.get(expiresInName).toString();
            if(StringUtils.isBlank(expiresIn)){
                LogUtils.error("token获取失败,获取结果" + expiresIn);
                return false;
            }
        } catch (Exception e) {
            LogUtils.error("token 结果解析失败，token参数名称: " + tokenName 
                    + "有效期参数名称:" + expiresInName
                    + "token请求结果:" + data);
            e.printStackTrace();
            return false;
        }
        return true;
    }
    private static Integer getInt(Map<String, Object> temp, String key) {
        Number number = (Number) temp.get(key);
        return number == null ? null : number.intValue();
    }
}
